//
// Created by gj on 16-2-21.
//

#ifndef ALLUTILS_THREADSHAREPOINTER_H
#define ALLUTILS_THREADSHAREPOINTER_H

#include "../pointer/PointerCounter.h"
#include "../pointer/PointerDeleter.h"
#include "../base/Runnable.h"
#include "Mutex.h"

template<class T, class Dealloc = DefMemDelete<T *> >
class ThreadSharePointer {
public:
    // 用一个野指针构造智能指针，这个指针如果在外面释放了一定会引起崩溃
    ThreadSharePointer(T *ptr = NULL) //
            : LOG_INIT_NAME_DEBUG("ThreadSharePointer")
            data(ptr) {
        LOG_W_FUNC("Share pointer from T*")
    }

    ThreadSharePointer(ThreadSharePointer &sp) //
            : LOG_INIT_NAME_DEBUG("ThreadSharePointer")
            data(NULL) {
        _copy(sp);
    }

    T *operator->() {
        return data;
    }

    const T *operator->() const {
        return data;
    }

    T &operator*() {
        return (*data);
    }

    const T &operator*() const {
        return (*data);
    }

    ThreadSharePointer &operator=(ThreadSharePointer &sp) {
        _copy(sp);
        return (*this);
    }

    ThreadSharePointer &operator=(T *pointer) {
        ThreadSharePointer asyncSharePointer(pointer);
        _copy(asyncSharePointer);
        return (*this);
    }

    bool isNull() const {
        return data == NULL;
    }

    virtual ~ThreadSharePointer() {
        _clear();
    }

protected:
    static CMutex MUTEX;

    LOG_CREATE_DEBUG
    // 指向实际的数据
    T *data;
    // 指针计数
    PointerCounter counter;
    // 内存释放器
    Dealloc relloc;

    void _clear() {
        T *_data_t = NULL;
        AutoMutex autoMutex(MUTEX);
        MUTEX.lock();
        if (counter.decCount() == 1) {
            if (data != NULL) {
                _data_t = data;
                data = NULL;
            }
        }
        LOG_I_FUNC("Share pointer --> %p", data)
        MUTEX.unlock();
        relloc(_data_t);
    }

    void _copy(ThreadSharePointer &sp) {
        MUTEX.lock();
        T *_data_t = data;
        data = sp.data;
        int _count = counter.copy(sp.counter);
        LOG_I_FUNC("--> Share pointer copy: %p, %d", data, counter.getCount())
        MUTEX.unlock();
        if (_count == 1) {
            relloc(_data_t);
        }
    }

};

template<class T, class Dealloc> CMutex ThreadSharePointer<T, Dealloc>::MUTEX;
typedef ThreadSharePointer<CRunnable> AsyncRunnable;
typedef ThreadSharePointer<CMutex> Mutex;

// --------------------------------------------- unit test --------------------------------------------------
#ifdef FLAG_UNIT_TESTING

void thread_share_pointer_unit_testing();

#endif

#endif //ALLUTILS_THREADSHAREPOINTER_H
